package com.sxhuayuan.parking.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;

import com.sxhuayuan.parking.entity.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sxhuayuan.parking.compenent.Filter;
import com.sxhuayuan.parking.compenent.Page;
import com.sxhuayuan.parking.compenent.Pageable;
import com.sxhuayuan.parking.dao.BaseDao;
import com.sxhuayuan.parking.dao.OrderRefundDao;
import com.sxhuayuan.parking.dto.SumDTO;
import com.sxhuayuan.parking.service.OrderRefundService;
import com.sxhuayuan.parking.service.OrderService;
import com.sxhuayuan.parking.utils.SettingUtils;
import com.sxhuayuan.parking.utils.SnowFlake;
import sun.management.resources.agent;

@Service("orderRefundServiceImpl")
public class OrderRefundServiceImpl extends BaseServiceImpl<OrderRefund, Long> implements OrderRefundService {

	@Autowired
	OrderRefundDao dao;
	@Autowired
	OrderService orderService;
	@Resource(name = "orderNoFactory")
	SnowFlake orderNoFactory;
	@PersistenceContext
	protected EntityManager entityManager;

	@Override
	public BaseDao<OrderRefund, Long> getDAO() {
		return dao;
	}

	@Override
	public OrderRefund createRefund(Order order, BigDecimal refundMoney, String note) {
		OrderRefund refund = new OrderRefund();
		refund.setOrder(order);
		refund.setIsSuccess(false);
		refund.setNote(note);
		refund.setRefundNo(String.valueOf(orderNoFactory.nextId()));
		refund.setRefundMoney(SettingUtils.get().setScale(refundMoney));
		dao.save(refund);
		return refund;
	}

	@Override
	public void refundSuccess(OrderRefund refund, String msg) {
		refresh(refund, LockModeType.PESSIMISTIC_WRITE);
		Order order = refund.getOrder();
		refund.setIsSuccess(true);
		refund.setError(msg);
		// 更新退款金额和手续费
		orderService.lock(order, LockModeType.PESSIMISTIC_WRITE);
		order.setRefundMoney(SettingUtils.get().setScale(refund.getRefundMoney().add(order.getRefundMoney())));
		ParkingLot lot = order.getParkingLot();
		order.setServiceCharge(lot.calcServiceFee(order.getPlatform(), order.getPaidMoney()));
		dao.save(refund);
	}

	@Override
	public BigDecimal[] sumByAgentAndDate(Agent agent, LocalDate date) {
		BigDecimal[] refunds = new BigDecimal[2];
		List<Object> objects = dao.sumByAgentAndCreateDate(agent.getId(), date.toString(), date.plusDays(1).toString());
		if (objects != null && objects.size() > 0) {
			Object[] list = (Object[]) objects.get(0);
			if (list != null) {
				refunds[0] = list[0] == null ? BigDecimal.ZERO : (BigDecimal) list[0];
				refunds[1] = list[1] == null ? BigDecimal.ZERO : (BigDecimal) list[1];
				return refunds;
			}
		}
		refunds[0] = BigDecimal.ZERO;
		refunds[1] = BigDecimal.ZERO;
		return refunds;
	}

	@Override
	public Page<OrderRefund> findPage(Pageable pageable, ParkingLotUser parkingLotUser) {

		StringBuilder sb = new StringBuilder("select r from OrderRefund r left join Order ord on r.order.id = ord.id ");
		if (parkingLotUser != null) {
			if (parkingLotUser.getParkingLots().size() <= 0) {
				return new Page<>();
			}
			Set<ParkingLot> parkingLots = parkingLotUser.getParkingLots();
			List<Long> ids = new ArrayList<>();
			for (ParkingLot parkingLot : parkingLots) {
				ids.add(parkingLot.getId());
			}
			if (ids.size() == 1) {
				sb.append(" where ord.parkingLot.id=").append(ids.get(0));
			} else {
				sb.append(" where ord.parkingLot.id in(").append(StringUtils.join(ids.toArray(), ',')).append(") ");
			}
		} else {
			sb.append("where 1=1 ");
		}
		List<Filter> filters = pageable.getFilters();
		if (filters != null) {
			for (Filter filter : filters) {
				setCondition(sb, filter);
			}
		}
		sb.append(" order by r.modifyDate desc");
		return findPage(sb.toString(), sb.toString().replace("select r", "select count(r.id)"), pageable.getPageSize(), pageable.getPageNumber());
	}

	@Override
	public SumDTO sumByFindPage(Pageable pageable, ParkingLotUser parkingLotUser) {
		SumDTO sumDTO = new SumDTO();
		sumDTO.setCount(0L);
		sumDTO.setAmount(BigDecimal.ZERO);
		StringBuilder sb = new StringBuilder("select count(r.id),sum(r.refundMoney) from OrderRefund r left join Order ord on r.order.id = ord.id ");
		if (parkingLotUser != null) {
			if (parkingLotUser.getParkingLots().size() <= 0) {
				return sumDTO;
			}
			Set<ParkingLot> parkingLots = parkingLotUser.getParkingLots();
			List<Long> ids = new ArrayList<>();
			for (ParkingLot parkingLot : parkingLots) {
				ids.add(parkingLot.getId());
			}
			if (ids.size() == 1) {
				sb.append(" where ord.parkingLot.id=").append(ids.get(0));
			} else {
				sb.append(" where ord.parkingLot.id in(").append(StringUtils.join(ids.toArray(), ',')).append(") ");
			}
		} else {
			sb.append("where 1=1 ");
		}

		List<Filter> filters = pageable.getFilters();
		if (filters != null) {
			for (Filter filter : filters) {
				setCondition(sb, filter);
			}
		}
		Object object = entityManager.createQuery(sb.toString()).getSingleResult();

		if (object != null) {
			Object[] result = (Object[]) object;
			sumDTO.setCount(result[0] == null ? 0L : (Long) (result[0]));
			sumDTO.setAmount(result[0] == null ? BigDecimal.ZERO : (BigDecimal) (result[1]));
		}
		return sumDTO;
	}

	private void setCondition(StringBuilder sb, Filter filter) {
		if (filter.getProperty() == null || "".equals(filter.getProperty()) || filter.getValue() == null || filter.getValue().equals("")) {
			return;
		}
		Object value = filter.getValue();
		switch (filter.getProperty()) {
		case "refundNo":
			sb.append(" and r.refundNo='").append(value).append("'");
			break;
		case "carPlate":
			sb.append(" and ord.carPlate='").append(value).append("'");
			break;
		case "parkingLotName":
			sb.append(" and ord.parkingLotName='").append(value).append("'");
			break;
		case "orderSn":
			sb.append(" and ord.sn='").append(value).append("'");
			;
			break;
		case "istartTime":
			sb.append(" and r.modifyDate>='").append(value).append("'");
			break;
		case "iendTime":
			sb.append(" and r.modifyDate<='").append(value).append("'");
			break;
		case "isSuccess": {
			if ("0".equals(value) || "1".equals(value)) {
				sb.append(" and r.isSuccess=").append("1".equals(value));
				break;
			}
			break;
		}
		default:
		}
	}

}
